package ferp.core.mode;

import ferp.core.calc.Calculator;
import ferp.core.card.Card;
import ferp.core.game.Bid;
import ferp.core.game.Game;
import ferp.core.game.Input;
import ferp.core.game.Settings;
import ferp.core.player.Hand;
import ferp.core.player.Player;
import ferp.core.player.Profile;
import ferp.core.state.State;
import ferp.core.tutorial.Scenario;

/**
 * User: olegs
 * Date: 18/06/11 22:13
 */
public class Dropping extends Mode
{
  public static void undo(Game.Listener listener, Game g)
  {
    // restore declarer's hand prior drop
    Game.HandData hd = g.getDeclarerHand();
    hd.current = hd.initial;

    // clear drop
    for (int i = 0; i < Game.TALON_SIZE; ++i)
      g.setDrop(i, 0);

    // clear input option
    g.options.clear();

    // switch to Dropping
    g.set(dropping);

    // show player bids again
    for (Player p : g.players())
      listener.showBid(p, g.getBid(p.id()), false);
  }

  @Override
  public int initialize(Game.Listener listener, Profile profile, Game g, Settings settings) throws Game.Error
  {
    // common mode initialization
    int r = super.initialize(listener, profile, g, settings);

    // deal talon to the declarer
    for (int i = 0; i < Game.TALON_SIZE; i++)
      g.getDeclarerHand().current = Hand.add(g.getDeclarerHand().current, g.getTalonHash(i));

    // fire talon taken event
    listener.onTalonTaken(g, settings);

    // show misere desk if misere declared by AI
    if (g.bid.isMisere() && g.declarer() != g.human())
      listener.showMisereDesk(g, settings, g.getDeclarerHand().current);

    return r;
  }

  @Override
  public void mark(Game.Listener listener, Game g)
  {
    int i = 0;

    for (int c : g.scenario().drop())
      listener.markCard(g.player.current, Card.card(c), i++);

    listener.markDrop();
  }

  @Override
  public void score(Game g, Settings settings)
  {
    // score
    Calculator.get(settings.gameFlavor).trickingWithout3(g, settings);

    // interrupt passing if configured
    if (settings.isPassingInterruptedByFailedGame())
      g.consequentPassingSets = 0;
  }

  @Override
  public Card.State getTalonCardState(Game g, Settings settings, int i)
  {
    return g.state() == State.initialize ? Card.State.FACE_UP : Card.State.HIDDEN;
  }

  @Override
  protected int getStartingPlayer(Game g)
  {
    // make declarer to be the starting player
    return g.player.declarer;
  }

  @Override
  protected int options(Game.Listener listener, Game g, Settings settings, Input input) throws Game.Error
  {
    // current player is always declarer here
    // in case of AI the method below may set input.bid to 'without 3'
    return g.current().setDroppingInputOptions(g, settings, input, g.options);
  }

  @Override
  protected Scenario.Note getOptionsNote(Game g, Settings settings)
  {
    return g.scenario().getDroppingOptionsNote();
  }

  @Override
  protected boolean validate(Game.Listener listener, Game g, Settings settings, Input input)
  {
    int[] drop = g.scenario().drop();
    boolean valid = (input.drop[0] | input.drop[1]) == (drop[0] | drop[1]);

    if (!valid)
      listener.onInvalidDrop();

    return valid;
  }

  @Override
  protected Act act(Game.Listener listener, Game g, Settings settings, Input input) throws Game.Error
  {
    // current player is always declarer here
    if (input.bid.type == Bid.Type.WITHOUT_3)
    {
      g.getDeclarerBid().current.type = Bid.Type.WITHOUT_3;
      listener.onPlayerContract(g.declarer(), g.getDeclarerBid());
    }
    else
    {
      // drop the cards
      g.declarer().drop(g, input);
      // drop declarer's cards stored in c.drop[]
      for (int i = 0; i < Game.TALON_SIZE; i++)
        g.getDeclarerHand().current = Hand.remove(g.getDeclarerHand().current, g.getDropHash(i));

      // fire event
      listener.onPlayerDrop(g, settings, g.declarer());
    }

    return Act.NEXT;
  }
  
  @Override
  protected boolean isRoundOver(Game g) {return true;}

  @Override
  protected void done(Game.Listener listener, Game g, Settings settings)
  {
    // end if declarer choose "without 3", otherwise
    // switch to "misere" mode if playing misere, otherwise to contracting mode
    if (g.getDeclarerBid().current.isWithout3())
      g.score();
    else
      if (g.getDeclarerBid().current.isMisere())
        g.set(g.declarer() == g.human() ? Mode.misereConfirm : Mode.misere);
      else
        g.set(Mode.contracting);
  }
}
